bitkeeper revision 1.1041.9.1 (40eac387W39rUFRFKTwvCfPBOF7Aow)
authormjw@wray-m-3.hpl.hp.com <mjw@wray-m-3.hpl.hp.com>
Tue, 6 Jul 2004 15:21:43 +0000 (15:21 +0000)
committermjw@wray-m-3.hpl.hp.com <mjw@wray-m-3.hpl.hp.com>
Tue, 6 Jul 2004 15:21:43 +0000 (15:21 +0000)
Convert most 'xm create' command-line switches to variables.

tools/python/xen/util/ip.py
tools/python/xen/xm/create.py
tools/python/xen/xm/opts.py

index 8396e0d01477efa7bb055e252fd6cd6e568e4509..39eb01f944405c8b967851987b012eca309d180a 100644 (file)
@@ -3,7 +3,7 @@ import re
 import socket
 import struct
 
-def readlines(fd):
+def _readlines(fd):
     """Version of readlines safe against EINTR.
     """
     import errno
@@ -21,7 +21,7 @@ def readlines(fd):
         lines.append(line)
     return lines
 
-def readline(fd):
+def _readline(fd):
     """Version of readline safe against EINTR.
     """
     while 1:
@@ -42,11 +42,14 @@ as it may have been moved onto the bridge.
 NBE_BRIDGE = 'nbe-br'
 
 def get_current_ipaddr(dev='eth0'):
-    """Return a string containing the primary IP address for the given
-    network interface (default 'eth0').
+    """Get the primary IP address for the given network interface.
+
+    dev     network interface (default eth0)
+
+    returns interface address as a string
     """
     fd = os.popen( '/sbin/ifconfig ' + dev + ' 2>/dev/null' )
-    lines = readlines(fd)
+    lines = _readlines(fd)
     for line in lines:
         m = re.search( '^\s+inet addr:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*',
                        line )
@@ -57,11 +60,14 @@ def get_current_ipaddr(dev='eth0'):
     return None
 
 def get_current_ipmask(dev='eth0'):
-    """Return a string containing the primary IP netmask for the given
-    network interface (default 'eth0').
+    """Get the primary IP netmask for a network interface.
+
+    dev     network interface (default eth0)
+
+    returns interface netmask as a string
     """
     fd = os.popen( '/sbin/ifconfig ' + dev + ' 2>/dev/null' )
-    lines = readlines(fd)
+    lines = _readlines(fd)
     for line in lines:
         m = re.search( '^.+Mask:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*',
                        line )
@@ -72,11 +78,14 @@ def get_current_ipmask(dev='eth0'):
     return None
 
 def get_current_ipgw(dev='eth0'):
-    """Return a string containing the IP gateway for the given
-    network interface (default 'eth0').
+    """Get the IP gateway for a network interface.
+
+    dev     network interface (default eth0)
+
+    returns gateway address as a string
     """
     fd = os.popen( '/sbin/route -n' )
-    lines = readlines(fd)
+    lines = _readlines(fd)
     for line in lines:
         m = re.search( '^\S+\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)' +
                        '\s+\S+\s+\S*G.*' + dev + '.*', line )
@@ -88,24 +97,46 @@ def get_current_ipgw(dev='eth0'):
 
 def inet_aton(addr):
     """Convert an IP addr in IPv4 dot notation into an int.
+
+    addr    IP address as a string
+
+    returns integer
     """
     b = socket.inet_aton(addr)
     return struct.unpack('!I', b)[0]
 
 def inet_ntoa(n):
     """Convert an int into an IP addr in IPv4 dot notation.
+
+    n       IP address
+
+    returns string
     """
     b = struct.pack('!I', n)
     return socket.inet_ntoa(b)
 
 def add_offset_to_ip(addr, offset):
     """Add a numerical offset to an IP addr in IPv4 dot notation.
+
+    addr    IP address
+    offset  offset to add
+
+    returns new address
     """
     n = inet_aton(addr)
     n += offset
     return inet_ntoa(n)
 
 def check_subnet( ip, network, netmask ):
+    """Check if an IP address is in the subnet defined by
+    a network address and mask'.
+
+    ip      IP adress
+    network network address
+    netmask network mask
+    
+    returns 1 if it is in the subnet, 0 if not
+    """
     n_ip = inet_aton(ip)
     n_net = inet_aton(network)
     n_mask = inet_aton(netmask)
index 3c61db9325e260b2037dd6241eb5971e1f4d77e9..cf82d075f9e6c513e52447f77495fdf40cde1189 100644 (file)
@@ -13,7 +13,7 @@ from xen.util import console_client
 
 from xen.xm.opts import *
 
-gopts = Opts(use="""[options]
+gopts = Opts(use="""[options] [vars]
 
 Create a domain.
 
@@ -66,54 +66,49 @@ gopts.opt('load', short='L', val='FILE',
           fn=set_value, default=None,
           use='Domain saved state to load.')
 
-#gopts.opt('define', short='D', val='VAR=VAL',
-#         fn=set_var, default=None,
-#         use="""Set a variable before loading defaults, e.g. '-D vmid=3'
-#         to set vmid. May be repeated to set more than one variable.""")
-
 gopts.opt('dryrun', short='n',
          fn=set_true, default=0,
          use="""Dry run - print the config but don't create the domain.
 The defaults file is loaded and the SXP configuration is created and printed.         
 """)
 
-gopts.opt('name', short='N', val='NAME',
-          fn=set_value, default=None,
-          use="Domain name.")
-
 gopts.opt('console_autoconnect', short='c',
          fn=set_true, default=0,
          use="Connect to console after domain is created.")
 
-gopts.opt('kernel', short='k', val='FILE',
+gopts.var('name', val='NAME',
+          fn=set_value, default=None,
+          use="Domain name.")
+
+gopts.var('kernel', val='FILE',
          fn=set_value, default=None,
          use="Path to kernel image.")
 
-gopts.opt('ramdisk', short='r', val='FILE',
+gopts.var('ramdisk', val='FILE',
          fn=set_value, default='',
          use="Path to ramdisk.")
 
-gopts.opt('builder', short='b', val='FUNCTION',
+gopts.var('builder', val='FUNCTION',
          fn=set_value, default='linux',
          use="Function to use to build the domain.")
 
-gopts.opt('memory', short='m', val='MEMORY',
+gopts.var('memory', val='MEMORY',
          fn=set_value, default=128,
          use="Domain memory in MB.")
 
-gopts.opt('autorestart',
-         fn=set_true, default=0,
+gopts.var('autorestart', val='no|yes',
+         fn=set_bool, default=0,
          use="Whether to restart the domain on exit.")
 
-gopts.opt('blkif',
-          fn=set_true, default=0,
+gopts.var('blkif', val='no|yes',
+          fn=set_bool, default=0,
           use="Make the domain a block device backend.")
 
-gopts.opt('netif',
-          fn=set_true, default=0,
+gopts.var('netif', val='no|yes',
+          fn=set_bool, default=0,
           use="Make the domain a network interface backend.")
 
-gopts.opt('disk', short='d', val='phy:DEV,VDEV,MODE',
+gopts.var('disk', val='phy:DEV,VDEV,MODE',
          fn=append_value, default=[],
          use="""Add a disk device to a domain. The physical device is DEV,
          which is exported to the domain as VDEV. The disk is read-only if MODE
@@ -121,18 +116,18 @@ gopts.opt('disk', short='d', val='phy:DEV,VDEV,MODE',
          The option may be repeated to add more than one disk.
          """)
 
-gopts.opt('pci', val='BUS,DEV,FUNC',
+gopts.var('pci', val='BUS,DEV,FUNC',
          fn=append_value, default=[],
          use="""Add a PCI device to a domain, using given params (in hex).
          For example '-pci c0,02,1a'.
          The option may be repeated to add more than one pci device.
          """)
 
-gopts.opt('ipaddr', short='i', val="IPADDR",
+gopts.var('ipaddr', val="IPADDR",
          fn=append_value, default=[],
          use="Add an IP address to the domain.")
 
-gopts.opt('vif', val="mac=MAC,bridge=BRIDGE",
+gopts.var('vif', val="mac=MAC,bridge=BRIDGE",
          fn=append_value, default=[],
          use="""Add a network interface with the given MAC address and bridge.
          If mac is not specified a random MAC address is used.
@@ -141,7 +136,7 @@ gopts.opt('vif', val="mac=MAC,bridge=BRIDGE",
          Specifying vifs will increase the number of interfaces as needed.
          """)
 
-gopts.opt('nics', val="NUM",
+gopts.var('nics', val="NUM",
          fn=set_int, default=1,
          use="""Set the number of network interfaces.
          Use the vif option to define interface parameters, otherwise
@@ -149,44 +144,44 @@ gopts.opt('nics', val="NUM",
          number of interfaces as needed.
          """)
 
-gopts.opt('root', short='R', val='DEVICE',
+gopts.var('root', val='DEVICE',
          fn=set_value, default='',
          use="""Set the root= parameter on the kernel command line.
          Use a device, e.g. /dev/sda1, or /dev/nfs for NFS root.""")
 
-gopts.opt('extra', short='E', val="ARGS",
+gopts.var('extra', val="ARGS",
          fn=set_value, default='',
          use="Set extra arguments to append to the kernel command line.")
 
-gopts.opt('ip', short='I', val='IPADDR',
+gopts.var('ip', val='IPADDR',
          fn=set_value, default='',
          use="Set the kernel IP interface address.")
 
-gopts.opt('gateway', val="IPADDR",
+gopts.var('gateway', val="IPADDR",
          fn=set_value, default='',
          use="Set the kernel IP gateway.")
 
-gopts.opt('netmask', val="MASK",
+gopts.var('netmask', val="MASK",
          fn=set_value, default = '',
          use="Set the kernel IP netmask.")
 
-gopts.opt('hostname', val="NAME",
+gopts.var('hostname', val="NAME",
          fn=set_value, default='',
          use="Set the kernel IP hostname.")
 
-gopts.opt('interface', val="INTF",
+gopts.var('interface', val="INTF",
          fn=set_value, default="eth0",
          use="Set the kernel IP interface name.")
 
-gopts.opt('dhcp', val="off|dhcp",
+gopts.var('dhcp', val="off|dhcp",
          fn=set_value, default='off',
          use="Set the kernel dhcp option.")
 
-gopts.opt('nfs_server', val="IPADDR",
+gopts.var('nfs_server', val="IPADDR",
          fn=set_value, default=None,
          use="Set the address of the NFS server for NFS root.")
 
-gopts.opt('nfs_root', val="PATH",
+gopts.var('nfs_root', val="PATH",
          fn=set_value, default=None,
          use="Set the path of the root NFS directory.")
 
@@ -315,7 +310,7 @@ def preprocess_vifs(opts):
         d = {}
         a = vif.split(',')
         for b in a:
-            (k, v) = b.strip().split('=')
+            (k, v) = b.strip().split('=', 1)
             k = k.strip()
             v = v.strip()
             if k not in ['mac', 'bridge']:
@@ -392,7 +387,7 @@ def main(argv):
     # Process remaining args as config variables.
     for arg in args:
         if '=' in arg:
-            (var, val) = arg.strip().split('=')
+            (var, val) = arg.strip().split('=', 1)
             gopts.setvar(var.strip(), val.strip())
     if opts.vals.config:
         pass
index 25f11abad2d4de2830f83d3f7ae5c3072281cd23..4f963b51465e6daff93c17d53fd444e0df511db5 100644 (file)
@@ -126,6 +126,42 @@ class Opt:
         """
         return self.specified_opt
 
+class OptVar(Opt):
+    """An individual option variable.
+    """
+    def __init__(self, opts, name,
+                 val=None, fn=None, use=None, default=None):
+        """Create an option.
+
+        opts    parent options object
+        name    name of the field it controls
+        val     string used to print option args in help.
+                If val is not specified the option has no arg.
+        fn      function to call when the option is specified.
+        use     usage (help) string
+        default default value if not specified on command-line
+        """
+        if val is None:
+            val = name.upper()
+        Opt.__init__(self, opts, name, val=val, fn=fn, use=use, default=default)
+        self.optkeys = []
+        self.optkeys.append(self.long)
+
+    def short_opt(self):
+        return None
+
+    def long_opt(self):
+        return None
+
+    def show(self):
+        print '%s=%s' %(self.optkeys[0], self.val) 
+        print
+        if self.use:
+            print '\t',
+            print self.use
+        if self.val:
+            print '\tDefault', self.default or 'None'
+
 class OptVals:
     """Class to hold option values.
     """
@@ -134,6 +170,13 @@ class OptVals:
 class Opts:
     """Container for options.
     """
+
+    imports = ["import sys",
+               "import os",
+               "import os.path",
+               "from xen.util.ip import *",
+               ]
+
     def __init__(self, use=None):
         """Options constructor.
 
@@ -168,6 +211,12 @@ class Opts:
         self.options_map[name] = x
         return x
 
+    def var(self, name, **args):
+        x = OptVar(self, name, **args)
+        self.options.append(x)
+        self.options_map[name] = x
+        return x     
+
     def setvar(self, var, val):
         """Set a default script variable.
         """
@@ -232,7 +281,14 @@ class Opts:
             else:
                 print >>sys.stderr, "Error: Unknown option:", k
                 self.usage()
-        return args
+        xargs = []
+        for arg in args:
+            (k, v) = arg.split('=', 1)
+            for opt in self.options:
+                if opt.specify(k, v): break
+            else:
+                xargs.append(arg)
+        return xargs
 
     def short_opts(self):
         """Get short options specifier for getopt.
@@ -257,6 +313,7 @@ class Opts:
     def usage(self):
         print 'Usage: ', self.argv[0], self.use or 'OPTIONS'
         for opt in self.options:
+            print
             opt.show()
 
     def load_defaults(self, help=0):
@@ -287,21 +344,22 @@ class Opts:
         globals = {}
         locals = {}
         locals.update(self.vars)
-        cmd = '\n'.join(["import sys",
-                         "import os",
-                         "import os.path",
-                         "from xen.xm.help import Vars",
-                         "from xen.util import ip",
-                         "xm_file = '%s'" % defaults,
-                         "xm_help = %d" % help,
-                         "xm_vars = Vars(xm_file, xm_help, locals())",
-                         ])
+        cmd = '\n'.join(self.imports + 
+                        [ "from xen.xm.help import Vars",
+                          "xm_file = '%s'" % defaults,
+                          "xm_help = %d" % help,
+                          "xm_vars = Vars(xm_file, xm_help, locals())"
+                          ])
         exec cmd in globals, locals
         try:
             execfile(defaults, globals, locals)
         except:
             if not help: raise
-        if help: return
+        if help:
+            print 'The following imports are done automatically:'
+            for x in self.imports:
+                print x
+            return
         # Extract the values set by the script and set the corresponding
         # options, if not set on the command line.
         vtypes = [ types.StringType,
@@ -322,6 +380,17 @@ def set_false(opt, k, v):
     """Set an option false."""
     opt.set(0)
 
+def set_bool(opt, k, v):
+    """Set a boolean option.
+    """
+    if v in ['yes']:
+        opt.set(1)
+    elif v in ['no']:
+        opt.set(0)
+    else:
+        opt.opts.err('Invalid value:' +v)
+        
+
 def set_value(opt, k, v):
     """Set an option to a valoue."""
     opt.set(v)
@@ -341,6 +410,6 @@ def append_value(opt, k, v):
 def set_var(opt, k, v):
     """Set a default script variable.
     """
-    (var, val) = v.strip().split('=')
+    (var, val) = v.strip().split('=', 1)
     opt.opts.setvar(var.strip(), val.strip())